#include "collisionshapeseditor.h"
#include "ui_collisionshapeseditor.h"
#include "../physics/collisionshapesdocument.h"
#include "../gameobjects/graphicsobject.h"
#include "../gameobjects/animation.h"
#include "../gameobjects/texture.h"
#include "../physics/collisionshapetools.h"
#include "../application.h"

#include <QButtonGroup>
#include <QUndoStack>
#include <QMimeData>
#include <QClipboard>

CollisionShapesEditor::CollisionShapesEditor(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CollisionShapesEditor)
{
    ui->setupUi(this);

    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);
    pCSD->resetDocument();
    ui->widgetCollisionShapesView->setCollShapesDoc(pCSD);

    initTools();

    ui->toolButtonSelectAndManipulate->click();

    ui->spinBoxCurrentFrame->setMinimum(0);

    connect(ui->pushButtonDone, SIGNAL(clicked()), this, SLOT(accept()));

    connect(ui->spinBoxCurrentFrame, SIGNAL(valueChanged(int)),
            this, SLOT(currentFrameChanged(int)));
    connect(ui->comboBoxCurrentAnimation, SIGNAL(currentIndexChanged(QString)),
            this, SLOT(currentAnimationChanged(QString)));

    ui->pushButtonZoomIn->setAutoRepeat(true);
    ui->pushButtonZoomIn->setAutoRepeatDelay(1);
    ui->pushButtonZoomOut->setAutoRepeat(true);
    ui->pushButtonZoomOut->setAutoRepeatDelay(1);

    connect(ui->pushButtonZoomIn, SIGNAL(clicked()),
            ui->widgetCollisionShapesView, SLOT(zoomIn()));
    connect(ui->pushButtonZoomOut, SIGNAL(clicked()),
            ui->widgetCollisionShapesView, SLOT(zoomOut()));
    connect(ui->pushButtonResetView, SIGNAL(clicked()),
            ui->widgetCollisionShapesView, SLOT(resetView()));

    connect(pCSD, SIGNAL(shapeSelectionChanged()),
            this, SLOT(onShapeSelectionChanged()));

    connect(QApplication::clipboard(), SIGNAL(dataChanged()),
            this, SLOT(onClipboardDataChanged()));

    onShapeSelectionChanged();
    onClipboardDataChanged();

    initializeGUI();
}

CollisionShapesEditor::~CollisionShapesEditor()
{
    disconnectUndoGUI();
    delete ui;
}

void CollisionShapesEditor::disconnectUndoGUI()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    QPointer<QUndoStack> currentFrameUndoStack = pCSD->currentCSUndoStack();

    if(currentFrameUndoStack)
    {
        disconnect(currentFrameUndoStack, SIGNAL(canUndoChanged(bool)),
                ui->toolButtonUndo, SLOT(setEnabled(bool)));
        disconnect(currentFrameUndoStack, SIGNAL(canRedoChanged(bool)),
                ui->toolButtonRedo, SLOT(setEnabled(bool)));
        disconnect(ui->toolButtonUndo, SIGNAL(clicked()),
                currentFrameUndoStack, SLOT(undo()));
        disconnect(ui->toolButtonRedo, SIGNAL(clicked()),
                currentFrameUndoStack, SLOT(redo()));
    }
}

void CollisionShapesEditor::connectUndoGUI()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    QPointer<QUndoStack> currentFrameUndoStack = pCSD->currentCSUndoStack();

    if(currentFrameUndoStack)
    {
        connect(currentFrameUndoStack, SIGNAL(canUndoChanged(bool)),
                ui->toolButtonUndo, SLOT(setEnabled(bool)));
        connect(currentFrameUndoStack, SIGNAL(canRedoChanged(bool)),
                ui->toolButtonRedo, SLOT(setEnabled(bool)));
        connect(ui->toolButtonUndo, SIGNAL(clicked()),
                currentFrameUndoStack, SLOT(undo()));
        connect(ui->toolButtonRedo, SIGNAL(clicked()),
                currentFrameUndoStack, SLOT(redo()));

        ui->toolButtonUndo->setEnabled(currentFrameUndoStack->canUndo());
        ui->toolButtonRedo->setEnabled(currentFrameUndoStack->canRedo());
    }
}


void CollisionShapesEditor::initializeGUI()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    QPointer<GraphicsObject> go = pCSD->graphicsObject();
    Q_ASSERT(go);

    if(go->hasAnimations())
    {
        GraphicsObject::AnimationSet anims = go->animations();

        foreach(QPointer<Animation> anim, anims)
        {
            ui->comboBoxCurrentAnimation->addItem(anim->id());
        }

        currentAnimationChanged(anims.first()->id());
    }
    else
    {
        ui->comboBoxCurrentAnimation->setEnabled(false);
        ui->spinBoxCurrentFrame->setEnabled(false);
        ui->checkBoxSameShapeForAllFrames->setEnabled(false);

        ui->widgetCollisionShapesView->updateView();
        connectUndoGUI();
    }
}

void CollisionShapesEditor::initTools()
{
    QButtonGroup* pButtonGroup = new QButtonGroup(this);
    pButtonGroup->setExclusive(true);

    pButtonGroup->addButton(ui->toolButtonCreateChain);
    pButtonGroup->addButton(ui->toolButtonCreateCircle);
    pButtonGroup->addButton(ui->toolButtonCreateEdge);
    pButtonGroup->addButton(ui->toolButtonCreateRect);
    pButtonGroup->addButton(ui->toolButtonCreatePoly);
    pButtonGroup->addButton(ui->toolButtonSelect);
    pButtonGroup->addButton(ui->toolButtonMove);
    pButtonGroup->addButton(ui->toolButtonSelectAndManipulate);

    CollisionShapeTool::initTools(ui->widgetCollisionShapesView);

    connect(ui->toolButtonSelect, SIGNAL(clicked()),
            this, SLOT(changeActiveTool()));
    connect(ui->toolButtonSelectAndManipulate, SIGNAL(clicked()),
            this, SLOT(changeActiveTool()));
    connect(ui->toolButtonCreateCircle, SIGNAL(clicked()),
            this, SLOT(changeActiveTool()));
    connect(ui->toolButtonCreateRect, SIGNAL(clicked()),
            this, SLOT(changeActiveTool()));
    connect(ui->toolButtonCreatePoly, SIGNAL(clicked()),
            this, SLOT(changeActiveTool()));

    // TODO: add connections for other tools
}

void CollisionShapesEditor::currentAnimationChanged(const QString &animID)
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    QPointer<GraphicsObject> go = pCSD->graphicsObject();
    Q_ASSERT(go);

    QPointer<Animation> anim = go->animationByID(animID);

    if(anim)
    {
        pCSD->setCurrentAnimation(anim);
        ui->spinBoxCurrentFrame->setMaximum(anim->numFrames() - 1);
        ui->spinBoxCurrentFrame->setValue(0);
        currentFrameChanged(0);
    }
}

void CollisionShapesEditor::currentFrameChanged(int nIndex)
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    disconnectUndoGUI();
    pCSD->setCurrentFrame(nIndex);
    connectUndoGUI();
}

void CollisionShapesEditor::changeActiveTool()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    QToolButton* pButton = qobject_cast<QToolButton*>(sender());
    Q_ASSERT(pButton);

    QPointer<CollisionShapeTool> cst;

    if(pButton == ui->toolButtonSelect)
    {
        cst = CollisionShapeTool::toolByName("Select");
    }
    else if(pButton == ui->toolButtonSelectAndManipulate)
    {
        cst = CollisionShapeTool::toolByName("SelectAndManipulate");
    }
    else if(pButton == ui->toolButtonCreateCircle)
    {
        cst = CollisionShapeTool::toolByName("CreateCircle");
    }
    else if(pButton == ui->toolButtonCreateRect)
    {
        cst = CollisionShapeTool::toolByName("CreateRectangle");
    }
    else if(pButton == ui->toolButtonCreatePoly)
    {
        cst = CollisionShapeTool::toolByName("CreatePoly");
    }
    // TODO: Add conditions for other tools

    Q_ASSERT(cst);

    connect(cst, SIGNAL(actionCanceled()), pCSD, SLOT(deselectAllShapes()));

    ui->widgetCollisionShapesView->setCurrentTool(cst);
}

void CollisionShapesEditor::onShapeSelectionChanged()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    ui->pushButtonCopyShapes->setEnabled(pCSD->selectedShapes().size() != 0);
}

void CollisionShapesEditor::onClipboardDataChanged()
{
    const QMimeData* pMimeData = QApplication::clipboard()->mimeData();

    if(pMimeData)
    {
        ui->pushButtonPasteShapes->setEnabled(!pMimeData->data("editor/shapes").isEmpty());
    }
    else
    {
        ui->pushButtonPasteShapes->setEnabled(false);
    }
}

void CollisionShapesEditor::on_pushButtonCopyShapes_clicked()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    pCSD->copySelectedShapes();
}

void CollisionShapesEditor::on_pushButtonPasteShapes_clicked()
{
    CollisionShapesDocument* pCSD = Application::app().collisionShapesDocument();
    Q_ASSERT(pCSD);

    pCSD->pasteShapes();
}
